<?php
// +----------------------------------------------------------------------
// | Author: yaoyihong <510974211@qq.com>
// | Site home: http://www.tpframe.com
// +----------------------------------------------------------------------
declare (strict_types = 1);
namespace app\common\controller;

use tpfcore\helpers\Json;
use tpfcore\Core;
use think\facade\Config;
use think\facade\View;
use think\exception\HttpResponseException;
use think\Response;
use think\facade\Request;
use think\facade\Db;
use think\App;
use think\exception\ValidateException;
use think\Validate;
use \think\facade\Filesystem;
use tpfcore\storage\Qiniu;
use tpfcore\storage\AliyunOss;
use OSS\Core\OssException;
use Upyun\Upyun;

/**
 * 系统通用控制器基类
 */
class ControllerBase
{
    // 当前类名称
    protected $class;
    // 当前控制器名称
    protected $name;
    // 请求参数
    protected $param;
    // 请求的POST参数
    protected $post;
    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;

    /**
     * 是否批量验证
     * @var bool
     */
    protected $batchValidate = false;

    /**
     * 控制器中间件
     * @var array
     */
    protected $middleware = [];
    
    /**
     * 构造方法
     * @access public
     * @param  App  $app  应用对象
     */
    public function __construct(App $app)
    {
        $this->app     = $app;
        $this->request = $this->app->request;

        // 初始化请求信息
        $this->initRequestInfo();

        // 当前类名
        $this->class = get_called_class();

        if (empty($this->name)) {
            // 当前模型名
            $name       = str_replace('\\', '/', $this->class);
            $this->name = basename($name);
            
            if (Config::get('route.controller_suffix')) {
                $suffix     = basename(dirname($name));
                $this->name = substr($this->name, 0, -strlen($suffix));
            }
        }

        // 控制器初始化
        $this->_initialize();
    }

    /**
     * 基类初始化
     */
    public function _initialize(){}
    /**
    * 数始化模板
    */
    public function fetch($template,$param=[]){

        return View::fetch($template,$param);

    }
    /**
     * 初始化请求信息
     */
    final private function initRequestInfo()
    {
        defined('IS_POST')          or define('IS_POST',         $this->request->isPost());
        defined('IS_GET')           or define('IS_GET',          $this->request->isGet());
        defined('IS_AJAX')          or define('IS_AJAX',         $this->request->isAjax());
        defined('MODULE_NAME')      or define('MODULE_NAME',     $this->app->http->getName());
        defined('CONTROLLER_NAME')  or define('CONTROLLER_NAME', $this->request->controller());
        defined('ACTION_NAME')      or define('ACTION_NAME',     $this->request->action());
        defined('URL')              or define('URL',             strtolower($this->request->controller() . '/' . $this->request->action()));
        defined('URL_MODULE')       or define('URL_MODULE',      strtolower($this->app->http->getName()) . '/' . URL);
        
        $this->param = $this->request->param();
        $this->post = $this->request->post();
    }
    
    /**
     * 系统跳转
     * array _data  里面包含1-4个值  分别为 status 状态  | message 消息 | url 链接 / data 数据
     * 分页面跳转与ajax/app调用
     * exam:
        or
        jump(['error','操作失败','Member/index',$data])
        or
        jump([40044,'用户未登录'])
        or
        jump([0,'登录成功',['token'=>'a46awfa1wf1aw6gawf']])
        or
        jump(40040,'操作非法',['token'=>'a46awfa1wf1aw6gawf'])

        说明： 
            页面跳转（web）   code为0表示成功     返回数据格式：[0,"操作成功","Index/index",[]]                       主要用于pc、微信、mobile
            api接口           code为0表示成功     返回数据格式：[0,"操作成功",['token'=>'a46awfa1wf1aw6gawf']]        主要用于app
     */
    final protected function jump($_data = [])
    {

        if(!is_array($_data) || count($_data)>4) return null;

        $default_data=[0,'',null,null];

        list($status, $message, $url,$data)=$_data+$default_data;
        
        $success  = RESULT_SUCCESS;
        $error    = RESULT_ERROR;
        $redirect = RESULT_REDIRECT;

        // status为数字的情况 写api

        if(is_numeric($status)){

            return json(['code'=>$status,"msg"=>$message,"data"=>$url])->send();

        }else{
            // 分配跳转类型
            switch ($status) {
                case $success  :$this->$success($message, (string)$url, $data?$data:[]);
                case $error    :$this->$error($message, (string)$url, $data?$data:[]);
                case $redirect :$this->$redirect((string)$url);
                default        :return $data;
            }
        }
    }
    /**
     * 系统跳转
     */
    final protected function tip($status = '', $message = '操作成功', $url = null, $data = '')
    {

        is_array($status) && list($status, $message, $url) = $status;
        
        $response = Response::create(View::layout(false)->fetch(Config::get("app.tip_tmpl"),['title'=>$message,'url'=>$url]), "html");

        throw new HttpResponseException($response);
    }
    /*
    * ajax数据操作
    */
    public function ajaxdata(){
        IS_AJAX && $this->jump($this->_ajaxdata($this->param));
    }

    /*
        传递的数据必须要有下面的一些值 ，不然就不通过
        $table  表名
        $colum  列名
        $columval  列值
        $key 主键名
        $keyval  主键值
    */
    protected function _ajaxdata($data){
        $validate = new Validate(["table"=>"require","colum"=>"require","columval"=>"require","key"=>"require","keyval"=>"require|regex:\d+"]);
        if(!$validate->check($data)){
            return [-4,$validate->getError(),null];
        }
        extract($data);
        $result = Db::name($table)->where([$key=>$keyval])->update([$colum=>$columval]);
        if($result){
            return [1, '操作成功',null];
        }
        return [0, '操作失败',null];
    }
    /*
    * 空操作
    */
    public function _empty(){
        $this->tip([0,"你访问的页面不存在",null]);
    }
    
    /*
        上传图片
     */
    public function upload(){

        config("app.default_return_type","json");

        $this->jump($this->_upload());
    }
    /**
    * kindeditor 的上传方式
    */
    public function kd_upload(){

        $result = $this->_kd_upload();

        die(json_encode($result));

    }




    /**
     * URL 重定向
     * @access protected
     * @param string    $url    跳转的 URL 表达式
     * @param array|int $params 其它 URL 参数
     * @param int       $code   http code
     * @param array     $with   隐式传参
     * @return void
     * @throws HttpResponseException
     */
    protected function redirect($url, $code = 302, $with = [])
    {

        $response = Response::create($url, 'redirect');

        $response->code($code)->with($with);

        throw new HttpResponseException($response);
    }
    /**
     * 操作成功跳转的快捷方法
     * @access protected
     * @param mixed  $msg    提示信息
     * @param string $url    跳转的 URL 地址
     * @param mixed  $data   返回的数据
     * @param int    $wait   跳转等待时间
     * @param array  $header 发送的 Header 信息
     * @return void
     * @throws HttpResponseException
     */
    protected function success(string $msg = '操作成功',string $url = null,array $data = [], $wait = 3, array $header = [])
    {

        if (is_null($url) && !is_null(Request::server('HTTP_REFERER'))) {
            $url = Request::server('HTTP_REFERER');
        } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) {
            $url = url($url);
        }

        $type = $this->getResponseType();

        $result = [
            'code' => 0,
            'msg'  => $msg,
            'data' => $data,
            'url'  => $url,
            'wait' => $wait,
        ];

        $jump_template=Config::get('app.dispatch_success_tmpl');

        if ('html' == strtolower($type)) {
           
            $result = View::fetch($jump_template, $result);

        }

        $response = Response::create($result, $type)->header($header)->options(['jump_template' => $jump_template]);

        throw new HttpResponseException($response);
    }

    /**
     * 操作错误跳转的快捷方法
     * @access protected
     * @param mixed  $msg    提示信息
     * @param string $url    跳转的 URL 地址
     * @param mixed  $data   返回的数据
     * @param int    $wait   跳转等待时间
     * @param array  $header 发送的 Header 信息
     * @return void
     * @throws HttpResponseException
     */
    protected function error($msg = '操作失败',string $url = null, $data = [], $wait = 3, array $header = [])
    {
        if (is_null($url)) {
            $url = Request::isAjax() ? '' : 'javascript:history.back(-1);';
        } elseif ('' !== $url && !strpos($url, '://') && 0 !== strpos($url, '/')) {
            $url = url($url);
        }

        $type = $this->getResponseType();
        $result = [
            'code' => -1,
            'msg'  => $msg,
            'data' => $data,
            'url'  => $url,
            'wait' => $wait,
        ];

        $jump_template=Config::get('app.dispatch_error_tmpl');

        if ('html' == strtolower($type)) {

            $result = View::fetch($jump_template, $result);
        }

        $response = Response::create($result, $type)->header($header)->options(['jump_template' => $jump_template]);

        throw new HttpResponseException($response);
    }
    /**
     * 获取当前的 response 输出类型
     * @access protected
     * @return string
     */
    protected function getResponseType()
    {
        return Request::isAjax()
            ? Config::get('app.default_ajax_return')
            : Config::get('app.default_return_type');
    }
    protected function _upload(){
        $files = request()->file();
        if($files){
            $upload_position = empty(config("config.upload_pic_position"))?"local":config("config.upload_pic_position");
            $size=empty(config("config.allow_upload_pic_size"))?2*1024*1024:config("config.allow_upload_pic_size")*1024;
            $ext=empty(config("config.allow_upload_pic_type"))?'jpg,png,gif':config("config.allow_upload_pic_type");
            /*
                可上传多张图片
            */
            $urls=[];
            $index=0;

            $key = key($files);

            $files=is_array($files[$key])?$files[$key]:$files;

            try {
                validate([$key=>"fileSize:$size|fileExt:$ext"])->check($files);

                foreach ($files as $key => $file) {
                    $suffix=$file->extension();   //取得后缀
                    // 要上传的文件
                    $tmp_file = $file->getPathname();
                    //保存云端的路径名
                    $filename="data/uploads/".date('Ymd') . "/" . md5((string)microtime(true)).".$suffix";
                    $urls[$index] = "/".$filename;
                    //上传到七牛云
                    if($upload_position == "qiniu"){
                        try{
                            
                            $listConfig = Core::loadModel("Qiniu","qiniu","logic")->getConfig("qiniu");

                        }catch(\Exception $e){

                            return [40045,"请先安装或配置好七牛云OSS"];

                        }  
                        if(empty($listConfig) || $listConfig['status']==0){
                            return [40045,"请先安装或配置好七牛云"];
                        }
                        $config = json_decode($listConfig['config'],true);
                        
                        $qiniu = new Qiniu($config['config']);

                        $list = Core::loadModel("Bucket","qiniu","logic")->getBucket(["where"=>["channel"=>"qiniu"],"order"=>"is_default desc","limit"=>1]);

                        if(empty($list)){

                            return ["error"=>DATA_NORMAL,"message"=>"请配置好你的bucket"];
                        }
                        $bucket = $list[0]['name'];

                        $result = $qiniu->putFile($bucket,$filename, $tmp_file);

                        if(!$result){
                            return [40045,$qiniu->getErrorMsg()];
                        }

                        if(empty($list[0]['oss_img_url'])){
                            $domain = "http://".$list[0]['endpoint']."/";
                            $urls[$index] = $domain.$filename; 
                        }else{
                            $urls[$index] = $list[0]['oss_img_url']."/".$filename; 
                        }

                    }

                    //上传到阿里云
                    elseif($upload_position=="aliyun_oss") {

                        try{

                            $listConfig = Core::loadModel("AliyunOss","aliyun_oss","logic")->getConfig("aliyun_oss");

                        }catch(\Exception $e){

                            return [40045,"请先安装或配置好阿里云OSS"];

                        }
                        

                        if(empty($listConfig) || $listConfig['status']==0){
                            return [40045,"请先安装或配置好OSS"];
                        }
                        $config = json_decode($listConfig['config'],true);

                        $list = Core::loadModel("Bucket","aliyun_oss","logic")->getBucket(["where"=>["channel"=>"aliyun_oss"],"order"=>"is_default desc","limit"=>1]);

                        if(empty($list)){

                            return [40045,"请配置好你的bucket"];
                        }

                        $config["config"]['endpoint']=$list[0]['endpoint'];
                        $config["config"]['bucket']=$list[0]['name'];
                        try {
                            $aliyun_oss = new AliyunOss($config['config']);
                            if(!$aliyun_oss->uploadFile($tmp_file,$filename)){
                                return [40045,$aliyun_oss->getErrorMsg()];
                            }

                            $urls[$index]=empty($list[0]['oss_img_url'])?"https://".$list[0]['name'].".".$list[0]['endpoint']."/".$filename:$list[0]['oss_img_url']."/".$filename;

                        } catch (\OssException $e) {
                            return [40045,$e->getErrorMsg()];
                        }
                    }
                    // 上传到又拍云
                    elseif($upload_position=="upyun"){
                        try{

                            $listConfig = Core::loadModel("Addon","upyun","logic")->getConfig("upyun");

                        }catch(\Exception $e){

                            return [40045,"请先安装或配置好又拍云OSS"];

                        }   
                        if(empty($listConfig->config)){
                            return [40045,"请先安装或配置好又拍云"];
                        }
                        $config = json_decode($listConfig->config,true)['config'];

                        try{
                            $serviceConfig = new \Upyun\Config($config['service_name'],$config['operator_name'],$config['operator_pwd']);
                            $client = new Upyun($serviceConfig);

                            $fh = fopen($tmp_file,"r");
                            $rsp = $client->write($filename, $fh);

                            $urls[$index]=$config['website']."/".$filename;
                        }catch(\Exception $e){
                            return [40045,$e->getMessage()];
                        }
                    }
                    else{

                        $urls[$index] = config("filesystem.disks.public.url").DIRECTORY_SEPARATOR.Filesystem::disk('public')->putFile('uploads', $file);

                    }
                    $index++;
                    
                }

                return [0,"上传成功",$urls];

            }catch (\think\exception\ValidateException $e) {

                return [40024,$e->getMessage()];
            }
            
        }else{
            return [40024,"没有上传的文件"];
        }
    }

    protected function _kd_upload(){
        if(request()->file()){
            $upload_position = empty(config("config.upload_pic_position"))?"local":config("config.upload_pic_position");
            $size=empty(config("config.allow_upload_pic_size"))?2*1024*1024:config("config.allow_upload_pic_size")*1024;
            $ext=empty(config("config.allow_upload_pic_type"))?'jpg,png,gif':config("config.allow_upload_pic_type");
            $key = array_keys($_FILES)[0];
            $file = request()->file($key);
            try{
                validate([$key=>"fileSize:$size|fileExt:$ext"])->check((array)$file);

                $suffix=$file->extension();   //取得后缀
                // 要上传的文件
                $tmp_file = $file->getPathname();  
                //保存云端的路径名
                $filename="data/uploads/".date('Ymd') . "/" . md5((string)microtime(true)).".$suffix";

                //上传到七牛云
                if($upload_position == "qiniu"){
                    $listConfig = Core::loadModel("Qiniu","qiniu","logic")->getConfig("qiniu");
                    if(empty($listConfig) || $listConfig['status']==0){
                        return [40045,"请先安装或配置好七牛云"];
                    }
                    $config = json_decode($listConfig['config'],true);
                    
                    $qiniu = new Qiniu($config['config']);

                    $list = Core::loadModel("Bucket","qiniu","logic")->getBucket(["where"=>["channel"=>"qiniu"],"order"=>"is_default desc","limit"=>1]);

                    if(empty($list)){

                        return ["error"=>DATA_NORMAL,"message"=>"请配置好你的bucket"];
                    }
                    $bucket = $list[0]['name'];

                    $result = $qiniu->putFile($bucket,$filename, $tmp_file);

                    if(!$result){
                        return ["error"=>DATA_NORMAL,"message"=>$qiniu->getErrorMsg()];
                    }else{

                        if(empty($list[0]['oss_img_url'])){
                            $domain = "http://".$list[0]['endpoint']."/";
                            $filename = $domain.$filename; 
                        }else{
                            $filename= $list[0]['oss_img_url']."/".$filename; 
                        }
                        return ['error' => DATA_DISABLE, 'url' => $filename , 'img_url'=>$filename];
                    }
                }

                //上传到阿里云
                elseif($upload_position=="aliyun_oss") {
                    $listConfig = Core::loadModel("AliyunOss","aliyun_oss","logic")->getConfig("aliyun_oss");

                    if(empty($listConfig) || $listConfig['status']==0){
                        return ["error"=>DATA_NORMAL,"message"=>"请先安装或配置好OSS"];
                    }
                    $config = json_decode($listConfig['config'],true);

                    $list = Core::loadModel("Bucket","aliyun_oss","logic")->getBucket(["where"=>["channel"=>"aliyun_oss"],"order"=>"is_default desc","limit"=>1]);

                    if(empty($list)){

                        return ["error"=>DATA_NORMAL,"message"=>"请配置好你的bucket"];
                    }

                    $config["config"]['endpoint']=$list[0]['endpoint'];
                    $config["config"]['bucket']=$list[0]['name'];
                    try {
                        $aliyun_oss = new AliyunOss($config['config']);

                        if(!$aliyun_oss->uploadFile($tmp_file,$filename)){
                            return ["error"=>DATA_NORMAL,"message"=>$aliyun_oss->getErrorMsg()];
                        }

                        $url=empty($list[0]['oss_img_url'])?"https://".$list[0]['name'].".".$list[0]['endpoint']."/".$filename:$list[0]['oss_img_url']."/".$filename;
                        
                        return ['error' => DATA_DISABLE, 'url' => $url , 'img_url'=>$url];

                    } catch (\OssException $e) {
                        return ["error"=>DATA_NORMAL,"message"=>$e->getErrorMsg()];
                    }
                }
                // 上传到又拍云
                elseif($upload_position=="upyun"){
                    $listConfig = Core::loadModel("Addon","upyun","logic")->getConfig();
                    if(empty($listConfig->config)){
                        return ["error"=>DATA_NORMAL,"message"=>"请先安装或配置好又拍云"];
                    }
                    $config = json_decode($listConfig->config,true)['config'];
                    if(empty($config['service_name']) || empty($config['operator_name']) || empty($config['operator_pwd']) || empty($config['website'])){
                        return ["error"=>DATA_NORMAL,"message"=>"请配置好又拍云后再试"];
                    }
                    try{
                        $serviceConfig = new \Upyun\Config($config['service_name'],$config['operator_name'],$config['operator_pwd']);
                        $client = new Upyun($serviceConfig);

                        $fh = fopen($tmp_file,"r");
                        $rsp = $client->write($filename, $fh);

                        $url=$config['website']."/".$filename;
                        return ['error' => DATA_DISABLE, 'url' => $url , 'img_url'=>$url];
                    }catch(\Exception $e){
                        return ["error"=>DATA_NORMAL,"message"=>$e->getMessage()];
                    }
                }
                // 存储在本地
                else{
                    
                    $url = config("filesystem.disks.public.url").DIRECTORY_SEPARATOR.Filesystem::disk('public')->putFile('uploads', $file);

                    return ['error' => DATA_DISABLE, 'url' => $url , 'img_url'=>$url];

                }
            }catch (\think\exception\ValidateException $e) {

                return ["error"=>DATA_NORMAL,"message"=>$e->getMessage()];
            }
        }else{
            return ["error"=>DATA_NORMAL,"message"=>"没有要上传的文件"];
        }
    }
}
